#include "ReciveClientConnect.h"
#include "LoadConfig.h"
#include "Utility.h"
#include <event2/event.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>


using namespace std;


IMPL_LOGGER(ReciveClientConnect,logger);

ReciveClientConnect::ReciveClientConnect()
{
    server_listen_socket = -1;
    m_event_base = NULL;
    m_sever_listen_event = NULL;

    init();
}

ReciveClientConnect::~ReciveClientConnect()
{
    
}

bool ReciveClientConnect::init()
{
    LOG4CPLUS_DEBUG(logger,"start init");

    if(!init_socket())
    {
        LOG4CPLUS_ERROR(logger,"init socket fail");
        return false;
    }

    LOG4CPLUS_DEBUG(logger,"init socket succ");

    if(!bind_addr())
    {
        LOG4CPLUS_ERROR(logger,"bind addr fail");
        return false;
    }

    LOG4CPLUS_DEBUG(logger,"bind addr succ");

    if(!start_listen())
    {
        LOG4CPLUS_ERROR(logger,"init event base fail");
        return false;
    }
    
    if(!init_event_base())
    {
        LOG4CPLUS_ERROR(logger,"init event base fail");
        return false;
    }

    LOG4CPLUS_DEBUG(logger,"init event base succ");
    LOG4CPLUS_DEBUG(logger,"end init");

    return true;
}

bool ReciveClientConnect::init_socket()
{
    LOG4CPLUS_DEBUG(logger,"init socket start");

    server_listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if(server_listen_socket == -1)
    {
        LOG4CPLUS_ERROR(logger,"create socket error:"<<strerror(errno));
        return false;
    }

    if(Utility::set_nonblock(server_listen_socket)!=0)
    {
        LOG4CPLUS_ERROR(logger,"set nonblock fail error: "<<strerror(errno));
        return false;
    }
    
    if(Utility::set_reuseaddr(server_listen_socket)!=0)
    {
        LOG4CPLUS_ERROR(logger,"set reuseaddr fail error: "<<strerror(errno));
        return false;
    }
    LOG4CPLUS_DEBUG(logger,"init socket end");
    
    return true;
}


bool ReciveClientConnect::bind_addr()
{
    LOG4CPLUS_DEBUG(logger,"bind addr start");

    server_address.sin_family = AF_INET;

    server_address.sin_port = htons(g_LoadConfig_Mgr::instance().m_server_port);
    
    server_address.sin_addr.s_addr = inet_addr(g_LoadConfig_Mgr::instance().m_server_ip.c_str());

    if(::bind(server_listen_socket,(struct sockaddr*)(&server_address),sizeof(server_address))==-1)
    {
        LOG4CPLUS_ERROR(logger,"bind socket error:"<<strerror(errno));
        return false;
    }
    
    LOG4CPLUS_DEBUG(logger,"bind socket succ");
    
    
    LOG4CPLUS_DEBUG(logger,"bind addr end");
    
    return true;
}

bool ReciveClientConnect::init_event_base()
{
    LOG4CPLUS_DEBUG(logger,"init event base");

    m_event_base = event_base_new();

    if(m_event_base==NULL)
    {

        LOG4CPLUS_ERROR(logger,"create event base fail");
        
        return false;
        
    }

    m_sever_listen_event = event_new(m_event_base,server_listen_socket,EV_READ|EV_PERSIST,server_listen_callback,this);

    if(m_sever_listen_event==NULL)
    {
        LOG4CPLUS_ERROR(logger,"create server listen event fail");
        return false;
    }

    LOG4CPLUS_DEBUG(logger,"create server listen event succ");

    event_add(m_sever_listen_event,NULL);
    
    LOG4CPLUS_DEBUG(logger,"end init event base");

    return true;
}

void ReciveClientConnect::start_thread(ReciveClientConnect &recvClient)
{
    LOG4CPLUS_DEBUG(logger,"start thread");
    
    event_base_dispatch(recvClient.m_event_base);

    LOG4CPLUS_DEBUG(logger,"end thread");
}

void ReciveClientConnect::server_listen_callback(evutil_socket_t fd,short what,void *arg)
{
    LOG4CPLUS_DEBUG(logger,"server listen call back,get a connect");

    ReciveClientConnect *recv_client=NULL;

    recv_client = static_cast<ReciveClientConnect*>(arg);

    if(recv_client==NULL)
    {
        LOG4CPLUS_ERROR(logger,"change to ReciveClientConnect fail");
        return ;
    }
    
    int32_t client_fd =-1;

    struct sockaddr_in client_addr;

    socklen_t client_len = sizeof(client_addr);
    
    client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);

    if(client_fd == -1)
    {
        LOG4CPLUS_DEBUG(logger,"get a socket error:"<<strerror(errno));
        return ;
    }

    LOG4CPLUS_DEBUG(logger,"get a connet addr:"<<inet_ntoa(client_addr.sin_addr));

    CLIENTSOCKET client_socket(new ClientSocket());

    if(client_socket==NULL)
    {
        LOG4CPLUS_DEBUG(logger,"new a client socket error:"<<strerror(errno));
        return ;
    }
    
    client_socket->m_client_fd = client_fd;

    client_socket->m_client_addr = client_addr;

    if(!g_GlobalDataQueue_Mgr::instance().m_client_socket_queue->push(client_socket))
    {
        LOG4CPLUS_DEBUG(logger,"insert into gloable client scoket queue failed");
        return ;
    }

    LOG4CPLUS_DEBUG(logger,"the client socket queue size: "<<g_GlobalDataQueue_Mgr::instance().m_client_socket_queue->size());
        
    LOG4CPLUS_DEBUG(logger,"init_read_event succ");
}

bool ReciveClientConnect::start_listen()
{
    if(listen(server_listen_socket,g_LoadConfig_Mgr::instance().m_listen_block)<0)
    {        
        LOG4CPLUS_ERROR(logger,"listen on port"<<g_LoadConfig_Mgr::instance().m_server_port<<"fail");
        return false;
    }
    return true;
}

